<?php
namespace Core\Libs\Handler;

class JabezException extends \RuntimeException {

	private static $errors = 0;

	public function __construct($message, $code, $previous = NULL) {

		parent::__construct($message, $code, $previous);
	}

	public static function throwErrors($message, $code = 0, $previous = NULL) {

		throw new JabezException($message, $code, $previous);
	}
}

class Error extends \RuntimeException {

	private static $_this = NULL;
	private static $Exception = NULL;
	private static $Previous = NULL;
	private static $errorTypeCaptured = NULL;
	private static $exceptionHandler = NULL;
	private static $exceptionHandlerStatus = TRUE;
	private static $errorHandlerStatus = TRUE;
	private static $messageToSuppressErrors = '_@@@@!!!!{[(>>>>_ATTENTION_MESSAGE_RESERVED_FOR_SUPPRESSING_ERRORS_GENERATED_BY_JABEZ_PHP_ERROR_HANDLER_<<<<)]}!!!!@@@@_';
	private static $displayErrors = TRUE;
	private static $exit = TRUE;
	private static $errors = 0;
	private static $_message = NULL;
	private static $_internal = array();
	private static $_code = NULL;
	private static $_severity = NULL;
	private static $_file = NULL;
	private static $_line = NULL;

	/*
	final public function __construct($message, $code = NULL, $antecedente = NULL) {

		//self::throwErrors($message, $code, $antecedente);
	}
	*/
	/*
	public function __construct() {

		if(empty(self::$_this)) {

			self::$_this = $this;
		}
	}*/

	final public static function getPreviousException() {

		return self::$Exception->getPrevious();
	}

	final public static function throwErrors($code, $message = NULL, $severity = 1, $file = NULL, $line = NULL, $internal = NULL, $previous = NULL, $called = NULL) {

		($called == 'Core\Uses\Exception') ? self::$exceptionHandler = 'Core\Uses\Exception' : self::$exceptionHandler = NULL;
		$numArgs =& func_num_args();
		$isObject = FALSE;
		$isString = FALSE;

		if(is_object($code)) {

			$isObject = TRUE;
		}

		elseif(is_string($code)) {

			$isString = TRUE;
		}

		if($isObject) {

			self::$errorTypeCaptured = 'Exception';
			self::$_message = $code->message;
			self::$_internal[] = $code->message;
			self::$_file = $code->file;
			self::$_line = $code->line;
			self::$_code = $code->code;

			if(!isset($code->_severity)) {

				self::$_severity = 1;
			}

			else {

				self::$_severity = $code->_severity;
			}

			unset($code);
			$newExeption = FALSE;
		}

		elseif($isString) {

			$arg0 = $code;
			$arg1 = $message;
			$message = $arg0;
			$code = $arg1;
			$severity = 1;
			$newExeption = TRUE;
			self::$_severity = $severity;
		}

		else {

			$arg0 = $severity;
			$arg1 = $file;
			$arg2 = $internal;
			$file = $arg0;
			$line = $arg1;
			$internal = $arg2;
			$severity = 1;
			$newExeption = TRUE;
		}

		if($newExeption) {

			if(self::$Exception === NULL) {

				self::$Exception = new \RuntimeException($message, $code, NULL);
			}

			else {

				self::$Exception->__construct($message, $code, NULL);
			}

			//if(!empty($internal)) {

				self::$_internal[] = $internal;
			//}

			if(!empty($severity)) {

				self::$_severity = $severity;
			}

			self::$Exception->file = $file;
			self::$Exception->line = $line;
			self::$_file = $file;
			self::$_line = $line;

			throw self::$Exception;
		}
	}

	final public static function throwError($errors = NULL) {

		$error =& error_get_last();
		$isCaptured = self::isCaptured($errors, $error);

		if(isset($error['type']) && $isCaptured && $error['message'] !== self::$messageToSuppressErrors) {

			throw \Core\Uses\Exception($error['message'], $error['code'], $error['file'], $error['line']);
			return TRUE;
		}

		else {

			return FALSE;
		}
	}

	final public static function getInstance() {

		if(empty(self::$_this)) {

			self::$_this = new \Core\Libs\Handler\Error();
		}

		return self::$_this;
	}

	final public function getInternalError() {

		return self::$_internal[count(self::$_internal) - 2];
	}

	final public static function getErrorFile() {

		return self::$_file;
	}

	final public static function getErrorLine() {

		return self::$_line;
	}

	final public static function setSeverity($severity = 1) {

		self::$Exception->_severity = $severity;
	}

	final public static function getSeverity() {

		return self::$Exception->_severity;
	}

	final public static function getSeverityAsString() {

		$severity = NULL;

		if(empty(self::$Exception->_severity)) {

			$severity = 'null';
		}

		elseif(self::$Exception->_severity <= 25) {

			$severity = 'low';
		}

		elseif(self::$Exception->_severity <= 75) {

			$severity = 'medium';
		}

		else {

			$severity = 'high';
		}

		return $severity;
	}

	final public static function suppressErrors() {

		@trigger_error(self::$messageToSuppressErrors, E_USER_WARNING);
	}

	final public static function isCaptured($errors = NULL, $error = NULL) {

		if(empty($errors)) {

			$errors = self::$errors;
		}

		if(!is_array($error)) {

			$error =& error_get_last();
		}

		if(isset($error['type'])) {

			return ((($error['type'] ^ $errors) - $errors) <= 0);
		}

		return FALSE;
	}

	final public static function setErrorReporting($errors = NULL) {

		if($errors === NULL) {

			self::$errors = E_ALL^E_USER_DEPRECATED^E_DEPRECATED^E_NOTICE;
		}

		else {

			self::$errors = $errors;
		}

		if(self::$errorHandlerStatus === FALSE) {

			error_reporting(self::$errors);
		}
	}

	final public static function restoreErrorReporting() {

		error_reporting(E_ALL^E_USER_DEPRECATED^E_DEPRECATED^E_NOTICE);
	}

	final public static function getErrors($errors = NULL, $init = 0) {

		if($init === 0 || $init === 1) {

			self::$errorHandlerStatus = TRUE;
			self::setErrorReporting($errors);
			set_error_handler('Core\Libs\Handler\Error::throwErrors', self::$errors);
		}

		if($init === 0 || $init === 2) {

			self::$exceptionHandlerStatus = TRUE;
			set_exception_handler('Core\Libs\Handler\Error::throwErrors');
		}
	}

	final public static function initErrorHandler($errors = NULL) {

		self::getErrors($errors, 1);
	}

	final public static function initExceptionHandler() {

		self::getErrors(NULL, 2);
	}

	final public static function restoreHandlers($errors = 'default') {

		self::restoreErrorHandler($errors);
		self::restoreExceptionHandler();
	}

	final public static function restoreErrorHandler($errors = 'default') {

		set_error_handler(function() {

			return FALSE;
		});

		self::$errorHandlerStatus = FALSE;

		if($errors !== 'default') {

			self::setErrorReporting($errors);
		}
	}

	final public static function restoreExceptionHandler() {

		set_exception_handler(function() {

			return FALSE;
		});

		self::$exceptionHandlerStatus = FALSE;
	}

	final public static function &getErrorTypeCaptured() {

		return self::$errorTypeCaptured;
	}

	final public static function &setErrorTypeCaptured($type) {

		self::$errorTypeCaptured =& $type;
	}

	final public static function setDisplayErrors($errors = TRUE) {

		self::$displayErrors =& $errors;
	}

	final public static function getDisplayErrors() {

		return self::$displayErrors;
	}

	final public static function setExit($exit = TRUE) {

		self::$exit =& $exit;
	}

	final public static function getExit() {

		return self::$exit;
	}

	final public static function &shutdown($flag = FALSE) {

		$error =& error_get_last();
		$isCaptured = self::isCaptured(NULL, $error);

		if(isset($error['type'])) {

			if(function_exists('ini_set')) {

				ini_set('display_errors', 1);
			}

			if(self::$errorTypeCaptured === 'Exception' && $error['message'] !== self::$messageToSuppressErrors) {

				if(self::$displayErrors) {

					ob_clean();
					(is_object(self::$Exception)) ? $trace = self::$Exception->getTraceAsString() : $trace = '';
					echo '<b>Exception\Error:</b> '.self::$_message.'<br><br><b>Internal Error:</b> ' . self::getInternalError() . ' <br><br><b>File:</b> '.self::$_file.'<br><br><b>Line:</b> '.self::$_line.'<br><br><b>Stack Trace:</b> <br>'.$trace.'<br>';
				}

				self::$exceptionHandler = NULL;
				self::$errorTypeCaptured = NULL;
			}

			elseif($isCaptured && self::$displayErrors && $error['message'] !== self::$messageToSuppressErrors) {

				ob_clean();
				echo '<b>Exception\Error:</b> '.$error['message'].'<br><br><b>Internal Error:</b> ' . self::getInternalError() . ' <br><br><b>File:</b> '.$error['file'].'<br><br><b>Line:</b> '.$error['line'].'<br><br><b>Stack Trace:</b> <br>';
				debug_print_backtrace();
			}
		}

		self::$displayErrors = TRUE;

		if(self::$exit) {

			exit();
		}

		else {

			self::$exit = TRUE;
		}
	}
}
?>